package main

import (
	"encoding/json"
	"fmt"
	"os"
	"sync"
	"time"
)

// 定义日志写入接口
type LogWriter interface {
	WriteLog(message string)
}

// 定义结构化日志键值对
type Field[T any] struct {
	Key   string
	Value T
}

// 定义日志级别
type LogLevel int

const (
	Debug LogLevel = iota
	Info
	Warn
	Error
	Fatal
)

func (l LogLevel) String() string {
	levels := []string{"Debug", "Info", "Warn", "Error", "Fatal"}
	if int(l) < len(levels) {
		return levels[l]
	}
	return "Unknown"
}

// 封装异步日志任务
type LogMessage struct {
	Level       LogLevel
	Message     string
	Fields      []Field[any]
	MinLogLevel LogLevel // 消息的最小日志级别判断标准
}

// 定义日志接口，包含添加输出器的方法
type Logger interface {
	Debug(message string, fields ...Field[any])
	Info(message string, fields ...Field[any])
	Warn(message string, fields ...Field[any])
	Error(message string, fields ...Field[any])
	Fatal(message string, fields ...Field[any])
	AddWriter(writer LogWriter)
	SetLevel(level LogLevel)
	Wait()
	Stop()
}

// 定义基础日志类，包含多个日志写入器
type BaseLogger struct {
	writers []LogWriter
	level   LogLevel
	mu      sync.RWMutex
}

// 定义异步日志类
type AsyncLogger struct {
	BaseLogger
	msgChan         chan LogMessage
	wg              sync.WaitGroup
	quitChan        chan struct{}
	drainWg         sync.WaitGroup // 用于等待消息处理完毕
	levelChangeChan chan LogLevel  // 用于通知日志级别变更
}

func NewBaseLogger() *BaseLogger {
	return &BaseLogger{
		level: Info,
	}
}

func NewAsyncLogger(level LogLevel, bufferSize int) *AsyncLogger {
	a1 := &AsyncLogger{
		BaseLogger: BaseLogger{
			level: level,
		},
		msgChan:         make(chan LogMessage, bufferSize),
		quitChan:        make(chan struct{}),
		levelChangeChan: make(chan LogLevel, 10), // 缓冲通道，避免阻塞
	}
	a1.wg.Add(1)
	go a1.process()
	return a1
}

func (a *AsyncLogger) process() {
	defer a.wg.Done()

	for {
		select {
		// 处理日志级别变更通知
		case <-a.levelChangeChan:
			// 日志级别已经在SetLevel方法中更新，这里只是消费通知
			// 不需要做任何事情
		// 处理日志消息
		case msg := <-a.msgChan:
			// 使用消息自己的最小日志级别判断标准，而不是当前的日志级别
			if msg.Level < msg.MinLogLevel {
				a.drainWg.Done() // 即使消息被过滤，也要减少计数
				continue
			}

			a.mu.RLock()
			logEntry := make(map[string]any)
			logEntry["message"] = msg.Message
			logEntry["level"] = msg.Level.String()
			logEntry["time"] = time.Now().Format("2006-01-02 15:04:05")
			for _, field := range msg.Fields {
				logEntry[field.Key] = field.Value
			}
			data, err := json.Marshal(logEntry)
			if err != nil {
				fmt.Println("Failed to marshal log entry:", err)
				a.mu.RUnlock()
				a.drainWg.Done() // 即使序列化失败，也要减少计数
				continue
			}
			logString := string(data)
			for _, writer := range a.writers {
				writer.WriteLog(logString)
			}
			a.mu.RUnlock()
			a.drainWg.Done() // 消息处理完毕，减少计数

		// 处理退出信号
		case <-a.quitChan:
			return
		}
	}
}

func (a *AsyncLogger) Wait() {
	a.drainWg.Wait()
}

func (a *AsyncLogger) Stop() {
	// 等待所有已发送的消息处理完毕
	a.drainWg.Wait()

	// 关闭退出通道并等待处理协程结束
	close(a.quitChan)
	a.wg.Wait()
}

func (a *AsyncLogger) SetLevel(level LogLevel) {
	// 不再等待drainWg，而是通过通道通知process方法
	a.mu.Lock()
	oldLevel := a.level
	a.level = level
	a.mu.Unlock()

	// 如果日志级别没有变化，则不需要通知
	if oldLevel == level {
		return
	}

	// 通过通道通知process方法日志级别已变更
	a.levelChangeChan <- level
}

func (a *AsyncLogger) log(level LogLevel, message string, fields ...Field[any]) {
	a.mu.Lock()
	// 获取当前日志级别作为消息的最小日志级别判断标准
	minLogLevel := a.level

	// 如果消息级别小于最小日志级别，则不发送
	if level < minLogLevel {
		return
	}

	// 增加等待计数
	a.drainWg.Add(1)

	// 发送消息到通道
	a.msgChan <- LogMessage{
		Level:       level,
		Message:     message,
		Fields:      fields,
		MinLogLevel: minLogLevel, // 设置消息的最小日志级别判断标准
	}
	a.mu.Unlock()
}

func (a *AsyncLogger) Debug(message string, fields ...Field[any]) {
	a.log(Debug, message, fields...)
}

func (a *AsyncLogger) Info(message string, fields ...Field[any]) {
	a.log(Info, message, fields...)
}

func (a *AsyncLogger) Warn(message string, fields ...Field[any]) {
	a.log(Warn, message, fields...)
}

func (a *AsyncLogger) Error(message string, fields ...Field[any]) {
	a.log(Error, message, fields...)
}

func (a *AsyncLogger) Fatal(message string, fields ...Field[any]) {
	a.log(Fatal, message, fields...)
	os.Exit(1)
}

func (b *BaseLogger) log(level LogLevel, message string, fields ...Field[any]) {
	b.mu.Lock()
	currentLevel := b.level
	b.mu.Unlock()
	if level < currentLevel {
		return
	}

	logEntry := make(map[string]any)
	for _, field := range fields {
		logEntry[field.Key] = field.Value
	}
	logEntry["message"] = message
	logEntry["level"] = level.String()
	logEntry["time"] = time.Now().Format("2006-01-02 15:04:05")
	data, err := json.Marshal(logEntry)
	if err != nil {
		fmt.Println("Failed to marshal log entry:", err)
		return
	}
	logString := string(data)
	for _, writer := range b.writers {
		writer.WriteLog(logString)
	}
}

// 实现Logger接口的Debug方法
func (b *BaseLogger) Debug(message string, fields ...Field[any]) {
	b.log(Debug, message, fields...)
}

// 实现Logger接口的Info方法
func (b *BaseLogger) Info(message string, fields ...Field[any]) {
	b.log(Info, message, fields...)
}

// 实现Logger接口的Warn方法
func (b *BaseLogger) Warn(message string, fields ...Field[any]) {
	b.log(Warn, message, fields...)
}

// 实现Logger接口的Error方法
func (b *BaseLogger) Error(message string, fields ...Field[any]) {
	b.log(Error, message, fields...)
}

// 实现Logger接口的Fatal方法
func (b *BaseLogger) Fatal(message string, fields ...Field[any]) {
	b.log(Fatal, message, fields...)
	os.Exit(1)
}

func (b *BaseLogger) Stop() {
	// 空方法，不需要return语句
}

func (b *BaseLogger) SetLevel(level LogLevel) {
	b.mu.Lock()
	b.level = level
	b.mu.Unlock()
}

// 实现Logger接口的AddWriter方法
func (b *BaseLogger) AddWriter(writer LogWriter) {
	b.writers = append(b.writers, writer)
}

// 定义控制台写入器
type ConsoleWriter struct{}

// 实现LogWriter接口的WriteLog方法
func (c *ConsoleWriter) WriteLog(message string) {
	fmt.Println(message)
}

// 定义文件写入器
type FileWriter struct {
	file *os.File
}

// 实现LogWriter接口的WriteLog方法
func (f *FileWriter) WriteLog(message string) {
	f.file.WriteString(message + "\n")
}

// filewriter 打开文件
func (f *FileWriter) Open(filename string) error {
	file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		return err
	}
	f.file = file
	return nil
}

// 主函数
func main() {
	// 创建基础日志类
	// var logger Logger = NewBaseLogger()
	// 创建控制台写入器
	consoleWriter := &ConsoleWriter{}
	// 创建文件写入器
	fileWriter := &FileWriter{}
	// 打开文件
	err := fileWriter.Open("log.txt")
	if err != nil {
		fmt.Println("Failed to open file:", err)
		return
	}
	defer fileWriter.file.Close()
	// 添加写入器
	// logger.AddWriter(consoleWriter)
	// logger.AddWriter(fileWriter)
	// // 写入日志
	// logger.Debug("This is a debug message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	// logger.Info("This is an info message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	// logger.Warn("This is a warning message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	// logger.Error("This is an error message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	// // logger.Fatal("This is a fatal message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	// // 设置日志级别
	// logger.SetLevel(Warn)
	// fmt.Println("设置日志级别为Warn")
	// // 写入日志
	// logger.Debug("This is a debug message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	// logger.Info("This is an info message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	// logger.Warn("This is a warning message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	// logger.Error("This is an error message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	// logger.Fatal("This is a fatal message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	var synclogger Logger = NewAsyncLogger(Debug, 100)
	synclogger.AddWriter(consoleWriter)
	synclogger.AddWriter(fileWriter)
	synclogger.Debug("This is a debug message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	synclogger.Info("This is an info message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	synclogger.Warn("This is a warning message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	synclogger.Error("This is an error message", Field[any]{"name", "John"}, Field[any]{"age", 20})
	synclogger.Wait()
	fmt.Println("设置日志级别为Error")
	synclogger.SetLevel(Error)
	synclogger.Debug("This is a debug message", Field[any]{"name", "John"}, Field[any]{"age", 20}, Field[any]{"time", time.Now()})
	synclogger.Info("This is an info message", Field[any]{"name", "John"}, Field[any]{"age", 20}, Field[any]{"time", time.Now()})
	synclogger.Warn("This is a warning message", Field[any]{"name", "John"}, Field[any]{"age", 20}, Field[any]{"time", time.Now()})
	synclogger.Error("This is an error message", Field[any]{"name", "John"}, Field[any]{"age", 20}, Field[any]{"time", time.Now()})

	synclogger.Stop()
}
